﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace DotNet.Common
{
    /// <summary>
    /// 通用算法类
    /// </summary>
    public static class CommonMath
    {
        /// <summary>
        /// 除法，大于或等于数学商的最小整数（int）
        /// </summary>
        /// <param name="data"></param>
        /// <param name="divider"></param>
        /// <returns></returns>
        public static int DividCeiling(int data, int divider)
        {
            int value = data / divider;
            if ((data % divider) == 0)
            {
                return value;
            }
            else
            {
                return (value + 1);
            }
        }

        /// <summary>
        /// 除法，大于或等于数学商的最小整数（int64）
        /// </summary>
        /// <param name="data"></param>
        /// <param name="divider"></param>
        /// <returns></returns>
        public static Int64 DividCeiling(Int64 data, Int64 divider)
        {
            Int64 value = data / divider;
            if ((data % divider) == 0)
            {
                return value;
            }
            else
            {
                return (value + 1);
            }
        }

        /// <summary>
        /// 计算整数数组的最大公约数
        /// </summary>
        /// <param name="array">整数数组</param>
        /// <returns>最大公约数</returns>
        public static int MaxDivisor(int[] array)
        {
            if (array == null || array.Length == 0)
                return 0;

            if (array.Length == 1)
                return array[0];

            int v1;
            int v2 = array[0];
            for (int i = 1; i < array.Length; i++)
            {
                v1 = array[i];
                v2 = MaxDivisor(v1, v2);
                if (v2 == 0)
                    break;
            }

            return v2;
        }

        /// <summary>
        /// 计算两个整数的最大公约数
        /// </summary>
        /// <param name="v1">值1</param>
        /// <param name="v2">值2</param>
        /// <returns></returns>
        public static int MaxDivisor(int v1, int v2)
        {
            if (v1 != 0 && v2 != 0)
            {
                do
                {
                    MinMax(v1, v2, out v1, out v2);
                    v2 %= v1;
                }
                while (v2 != 0);

                return v1;
            }
            else if (v1 == 0)
                return v2;
            else if (v2 == 0)
                return v1;
            else //(v1 == 0 && v2 == 0)
                return 0;
        }

        /// <summary>
        /// 两个整数的最大最小值
        /// </summary>
        /// <param name="v1">值1</param>
        /// <param name="v2">值2</param>
        /// <param name="min">计算最小值结果</param>
        /// <param name="max">计算最大值结果</param>
        public static void MinMax(int v1, int v2, out int min, out int max)
        {
            if (v1 < v2)
            {
                min = v1;
                max = v2;
            }
            else
            {
                min = v2;
                max = v1;
            }
        }

        public static bool MinMax(double[] array, out double min, out double max)
        {
            min = double.MaxValue;
            max = double.MinValue;

            if (array == null || array.Length == 0)
                return false;

            min = max = array[0];
            foreach (double data in array)
            {
                if (data < min)
                    min = data;
                else if (data > max)
                    max = data;
            }

            return (min <= max);
        }

        /// <summary>
        /// 计算一元一次方程的解（曲线过〇点）,结果为x1 * y0 / x0,适用于x1 * y0溢出的情形
        /// </summary>
        /// <param name="x1">x1,乘数</param>
        /// <param name="y0">y0,被除数</param>
        /// <param name="x0">x0,除数</param>
        /// <returns>y1,解</returns>
        public static int OneVarEquation(int x1, int y0, int x0)
        {
            Debug.Assert(x0 != 0);

            return (int)Math.Round((double)x1 * y0 / x0);
        }

        /// <summary>
        /// 获取范围内的整型数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static int Nearest(int data, int min, int max)
        {
            if (min > max)
                return data;

            if (data < min)
                return min;
            else if (data > max)
                return max;
            else
                return data;
        }

        /// <summary>
        /// 获取范围内的双精度数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static double Nearest(double data, double min, double max)
        {
            if (min > max)
                return data;

            if (data < min)
                return min;
            else if (data > max)
                return max;
            else
                return data;
        }

        /// <summary>
        /// 计算复数的绝对值
        /// </summary>
        /// <param name="r"></param>
        /// <param name="i"></param>
        /// <returns></returns>
        public static double AbsComplex(float r, float i)
        {
            return Math.Sqrt(r * r + i * i);
        }

        /// <summary>
        /// 计算复数的绝对值
        /// </summary>
        /// <param name="r"></param>
        /// <param name="i"></param>
        /// <returns></returns>
        public static double AbsComplex(double r, double i)
        {
            return Math.Sqrt(r * r + i * i);
        }
    }
}
